<template>
  <BoTable
    ref="tableRef"
    :columns="subColumns"
    :request="_fetchList"
    :autoload="false"
    show-index
    hide-search
    hide-pagination
    children-column-name="none"
    :height="height"
  >
    <template #customTable="{ Table }">
      <div class="w-full flex-1 overflow-hidden" ref="wrapRef">
        <div ref="contentRef">
          <h3 class="module-title">
            {{ MonitoringTypeEnum[parentMonitorType] }}列表
          </h3>
          <ATable
            class="flex-unset mb-4"
            key="custom"
            :columns="parentColumns"
            :data-source="currentTableData"
            children-column-name="none"
            :pagination="false"
            :scroll="{ x: 500 }"
          />
          <h3 class="module-title" v-if="MonitoringTypeEnum[subMonitorType]">
            {{ MonitoringTypeEnum[subMonitorType] }}列表
          </h3>
        </div>
        <component v-if="MonitoringTypeEnum[subMonitorType]" :is="Table" />
      </div>
    </template>
    <template #leftContainer>
      <div class="mr-4 w-48 border-r border-[rgba(255,255,255,.3)]">
        <div class="mr-2 flex h-10 items-center justify-between">
          <h3 class="module-title mb-0 mr-7">监测列表</h3>
          <Button type="primary" size="small" @click="() => onAddOrUpdate()"
            >新增</Button
          >
        </div>
        <Tree
          :selected-keys="selectKeys"
          :expanded-keys="expandedKeys"
          :tree-data="treeData"
          :field-names="{ key: 'key' }"
        >
          <template #title="scope">
            <span @click="() => handleSelectMonitoringType(scope)">{{
              scope.structureName
            }}</span>
          </template>
        </Tree>
      </div>
    </template>
  </BoTable>
  <FormModal :columns="items"></FormModal>
</template>

<route lang="json">
{
  "name": "structure",
  "meta": {
    "title": "监测结构管理"
  }
}
</route>

<script setup lang="tsx">
import { computed, onMounted, ref, useTemplateRef } from 'vue';
import { useFormModal } from '@boeyo/hooks';
import { useDicts } from '@boeyo/portal';
import { listToEnum, listToOption, treeToArray } from '@boeyo/shared';
import { BoFormProps, BoTable, BoTableProps } from '@boeyo/ui';
import { useElementSize } from '@vueuse/core';
import {
  Table as ATable,
  Button,
  Modal,
  Space,
  TableProps,
  Tree,
} from 'ant-design-vue';
import LonLat from '@/components/LonLat/index.vue';
import {
  createAndUpdateStructure,
  deleteMonitor,
  fetchStructureTree,
  getAreaCode,
  projectSelectList,
} from './api';
import Floors from './components/Floors.vue';

interface Tree {
  id: number;
  children: Tree[];
  [key: string]: any;
}

const wrapRef = useTemplateRef('wrapRef');
const contentRef = useTemplateRef('contentRef');
const { height: wrapHeight } = useElementSize(wrapRef);
const { height: contentHeight } = useElementSize(contentRef);

const height = computed(() => wrapHeight.value - contentHeight.value - 50);

const tableRef = useTemplateRef('tableRef');
const _fetchList = () => {
  const rows = currentTableData.value[0].children;
  return {
    rows: rows || [],
    total: rows?.length || 0,
  };
};

/**
 * 1 监测网 2 监测区 3 监测阵
 */
type MonitoringType = '1' | '2' | '3';
const monitoringType = ref<MonitoringType>('1');
enum MonitoringTypeEnum {
  '监测网' = 1,
  '监测区',
  '监测阵',
}

const projectOptions = ref([]);
const projectEnum = ref({});
const projectList = ref([]);
const provinces = ref([]);
const expandedKeys = ref([]);

onMounted(() => {
  projectSelectList().then((res) => {
    projectList.value = res.data;
    projectOptions.value = listToOption(res.data, 'name', 'projectId');
    projectEnum.value = listToEnum(res.data, 'name', 'projectId');
  });

  getAreaCode().then((res) => {
    provinces.value = listToOption(res.data, 'name', 'shortCode');
  });
});
const { architecturalTypeOptions, monitorTypeOptions } = useDicts([
  'architectural_type',
  'monitor_type',
]);

const getSubMonitorType = (type) => {
  return ++type;
};

const parentMonitorType = computed(
  () => currentTableData.value[0]?.monitoringType,
);
const subMonitorType = computed(() =>
  getSubMonitorType(currentTableData.value[0]?.monitoringType),
);
const subColumnMonitorType = computed(() =>
  getSubMonitorType(currentTableData.value[0]?.children?.[0]?.monitoringType),
);

const parentColumns = computed<TableProps['columns']>(() => {
  return [
    {
      title: '序号',
      align: 'center',
      width: 80,
      customRender(opt) {
        return opt.renderIndex + 1;
      },
    },
    {
      title: `${MonitoringTypeEnum[parentMonitorType.value] || ''}编号`,
      align: 'center',
      width: 200,
      dataIndex: 'monitoringCode',
    },
    {
      title: `${MonitoringTypeEnum[parentMonitorType.value] || ''}名称`,
      align: 'center',
      width: 200,
      dataIndex: 'structureName',
    },
    {
      title: '省份',
      align: 'center',
      width: 200,
      dataIndex: 'province',
      hidden: +parentMonitorType.value !== 1,
    },
    {
      title: `涵盖${MonitoringTypeEnum[subMonitorType.value] || ''}数量`,
      align: 'center',
      width: 200,
      dataIndex: 'count',
    },
    {
      title: `创建人`,
      align: 'center',
      width: 200,
      dataIndex: 'createBy',
    },
    {
      title: `创建时间`,
      align: 'center',
      width: 200,
      dataIndex: 'createTime',
    },
    {
      title: `操作`,
      align: 'center',
      dataIndex: 'actions',
      fixed: 'right',
      width: 126,
      customRender({ record }) {
        return (
          <Space>
            <Button type='link' onClick={() => onAddOrUpdate(record)}>
              编辑
            </Button>
            <Button
              type='link'
              onClick={() =>
                onDelete(record, MonitoringTypeEnum[parentMonitorType.value])
              }
            >
              删除
            </Button>
          </Space>
        );
      },
    },
  ].filter((v) => !v.hidden) as TableProps['columns'];
});

const subColumns = computed<BoTableProps['columns']>(() => {
  return [
    {
      title: `${MonitoringTypeEnum[subMonitorType.value] || ''}编号`,
      dataIndex: 'monitoringCode',
      valueType: 'input',
    },
    {
      title: `${MonitoringTypeEnum[subMonitorType.value] || ''}名称`,
      dataIndex: 'structureName',
      valueType: 'input',
    },
    {
      title: `${MonitoringTypeEnum[subColumnMonitorType.value] || ''}数量`,
      dataIndex: 'count',
      hideInTable: subColumnMonitorType.value === 4,
      valueType: 'input',
    },
    {
      title: `关联项目`,
      dataIndex: 'projectId',
      valueType: 'select',
      valueEnum: {
        ...projectEnum.value,
      },
      hideInTable: subColumnMonitorType.value !== 4,
    },
    {
      title: '创建人',
      dataIndex: 'createBy',
      valueType: 'input',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      valueType: 'input',
    },
    {
      title: '操作',
      dataIndex: '_actions',
      fixed: 'right',
      valueType: 'input',
      actions() {
        return [
          {
            text: '编辑',
            onClick(record) {
              onAddOrUpdate(record);
            },
          },
          {
            text: '删除',
            onClick(record) {
              onDelete(record, MonitoringTypeEnum[subMonitorType.value]);
            },
          },
        ];
      },
    },
  ];
});

const prefix = computed(() => MonitoringTypeEnum[monitoringType.value]);
const selectKeys = ref([]);
const handleSelectMonitoringType = (scope) => {
  if (scope.disabled) return;
  selectKeys.value = [scope.key];
  currentTableData.value = [scope];
  tableRef.value.refresh();
};

const treeData = ref([]);
const selectTreeData = ref([]);
const currentTableData = ref([]);
const findTree = (key, tree: Tree[]) => {
  const result = {};
  const stack = [...tree];
  while (stack.length > 0) {
    const node = stack.pop();
    if (node.children?.length) {
      stack.unshift(...node.children);
    }
    if (node.value === key) {
      Object.assign(result, node);
      break;
    }
  }
  return result as Tree;
};
const formatTree = (
  tree: Tree[],
  opt: {
    label?: string;
    value?: string;
    children?: string;
    disabled: (data?: Record<string, any>) => boolean;
  },
) => {
  const {
    label = 'label',
    value = 'value',
    disabled = () => false,
    children = 'children',
  } = opt;

  const result = [];
  const stack = [...tree];
  const nodeMap = new Map();

  while (stack.length > 0) {
    const node = stack.shift();
    const formattedNode = {
      title: node[label],
      key: node[value],
      ...node,
      label: node[label],
      value: node[value],
      disabled: disabled(node),
      children: [],
    };
    nodeMap.set(node, formattedNode);
    const parentNode = nodeMap.get(node.parent);
    if (parentNode) {
      parentNode.children.push(formattedNode);
    } else {
      result.push(formattedNode);
    }
    if (node[children]) {
      node[children].forEach((child: any) => {
        child.parent = node;
        stack.push(child);
      });
    }
  }

  return result;
};
const refreshTreeData = async () => {
  const res = await fetchStructureTree();
  treeData.value = formatTree(res.data, {
    label: 'structureName',
    value: 'id',
    disabled: () => false,
  });

  selectTreeData.value = formatTree(res.data, {
    label: 'structureName',
    value: 'id',
    disabled(data) {
      return data.monitoringType === '3';
    },
  });
  expandedKeys.value = treeToArray(treeData.value).map((item) => item.id);

  currentTableData.value =
    MonitoringTypeEnum[subMonitorType.value] && treeData.value?.length
      ? [treeData.value.at(0)]
      : [];

  if (selectKeys.value.length && MonitoringTypeEnum[subMonitorType.value]) {
    const scope = findTree(selectKeys.value[0], treeData.value);
    handleSelectMonitoringType(scope);
  } else {
    handleSelectMonitoringType(treeData.value[0]);
  }
};
onMounted(() => {
  refreshTreeData();
});

const items = computed<BoFormProps['columns']>(() => {
  return [
    {
      title: `上级`,
      dataIndex: 'pid',
      valueType: 'treeSelect',
      fieldProps: {
        treeData: selectTreeData.value,
        disabled: isEdit.value,
        treeExpandedKeys: expandedKeys.value,
        onChange(value) {
          if (!value) {
            monitoringType.value = '1';
            return;
          }
          const result = findTree(value, treeData.value);
          monitoringType.value =
            `${getSubMonitorType(result.monitoringType)}` as MonitoringType;
        },
      },
    },
    {
      title: `${prefix.value}编号`,
      dataIndex: 'monitoringCode',
      valueType: 'input',
      formItemProps: {
        rules: [{ required: true, message: '请输入编号' }],
      },
    },
    {
      title: `${prefix.value}名称`,
      dataIndex: 'structureName',
      valueType: 'input',
      formItemProps: {
        rules: [{ required: true, message: '请输入名称' }],
      },
    },
    {
      title: `省份`,
      dataIndex: 'provinceCode',
      valueType: 'select',
      hidden: () => monitoringType.value !== '1',
      fieldProps: {
        options: provinces.value,
      },
      formItemProps: {
        rules: [{ required: true, message: '请选择省份' }],
      },
    },
    {
      title: `项目名称`,
      dataIndex: 'projectId',
      valueType: 'select',
      hidden: () => monitoringType.value !== '3',
      fieldProps() {
        return {
          options: projectOptions.value,
        };
      },
      formItemProps: {
        rules: [{ required: true, message: '请选择项目' }],
      },
    },
    {
      title: '监测类型',
      dataIndex: 'monitorArrayType',
      valueType: 'select',
      hidden: () => monitoringType.value !== '3',
      fieldProps: {
        options: monitorTypeOptions.value as any,
      },
    },
    {
      title: '经纬度',
      dataIndex: 'lon',
      valueType: 'inputNumber',
      hidden: () => monitoringType.value !== '3',
      formItemProps: {
        rules: [{ required: true, message: '请输入经纬度' }],
      },
      render(state) {
        return <LonLat v-model:lon={state.lon} v-model:lat={state.lat} />;
      },
    },
    {
      title: '建筑结构类型',
      dataIndex: 'architecturalType',
      valueType: 'select',
      hidden: (state) => state.monitorArrayType !== '1',
      fieldProps: {
        options: architecturalTypeOptions.value as any,
      },
    },
    {
      title: '环境描述',
      dataIndex: 'environment',
      valueType: 'textarea',
      hidden: (state) => state.monitorArrayType !== '1',
      formItemProps: {},
      fieldProps: {
        placeholder: '请输入环境描述',
      },
    },
    {
      title: '观测系统描述',
      dataIndex: 'systemDesc',
      valueType: 'textarea',
      hidden: (state) => state.monitorArrayType !== '1',
      formItemProps: {
        rules: [],
      },
      fieldProps: {
        placeholder: '请输入观测系统描述',
      },
    },
    {
      title: '建筑描述',
      dataIndex: 'building',
      valueType: 'textarea',
      hidden: (state) => state.monitorArrayType !== '1',
      formItemProps: {
        rules: [],
      },
      fieldProps: {
        placeholder: '请输入建筑描述',
      },
    },
    {
      title: `描述`,
      dataIndex: 'remark',
      valueType: 'textarea',
    },
    {
      title: '各层高度',
      dataIndex: 'floors',
      valueType: 'input',
      colProps: {
        span: 24,
      },
      hidden: (state) => state.monitorArrayType !== '1',
      render(state) {
        return <Floors v-model:value={state.floors} />;
      },
    },
  ];
});
const { FormModal, open } = useFormModal({
  column: 2,
  size: 'middle',
  bodyHeight: '400px',
  formProps: {
    labelCol: { style: { width: '100px' } },
    wrapperCol: { style: { width: '100%' } },
  },
  afterClose() {
    monitoringType.value = '1';
  },
});

const isEdit = ref(false);
const onAddOrUpdate = (record?: Record<string, any>) => {
  isEdit.value = false;
  if (record) {
    isEdit.value = true;
    monitoringType.value = record.monitoringType;
  }
  open({
    title: () => `${isEdit.value ? '编辑' : '新增'}${prefix.value}`,
    defaultValue: { ...record },
    request: async function (params: any) {
      const {
        id,
        monitoringCode,
        pid,
        projectId,
        provinceCode,
        remark,
        structureName,
        architecturalType,
        floors,
        environment,
        systemDesc,
        building,
        monitorArrayType,
        lon,
        lat,
      } = params;

      const projectName = projectEnum[projectId];
      const _params = {
        id,
        monitoringCode,
        pid,
        projectId,
        provinceCode,
        remark,
        structureName,
        projectName,
        monitoringType: monitoringType.value,
        architecturalType,
        floors,
        environment,
        systemDesc,
        building,
        monitorArrayType,
        lon,
        lat,
      };
      await createAndUpdateStructure(_params);
      refreshTreeData();
    },
  });
};

const onDelete = (record, desc) => {
  Modal.confirm({
    title: '提示',
    content: `确认删除该${desc}吗？`,
    async onOk() {
      await deleteMonitor(record.id);
      refreshTreeData();
    },
  });
};
</script>
